#pragma once 

namespace Melting
{
	template< class TData, typename Counter, UINT32 MAXDATA >
	struct StaticArray
	{
		Counter     muiNbData;
		TData       maData[ MAXDATA ];

		inline StaticArray( void )
		: muiNbData ( 0 )
		{
		}

		inline Counter          GetSize( void ) const
		{
			return muiNbData;
		}

		inline UINT32			GetCapacity( void ) const
		{
			return MAXDATA;
		}

		inline const TData&     operator[] ( int _iSlot ) const
		{
			return maData[ _iSlot ];
		}

		inline TData&           operator[] ( int _iSlot )
		{
			return maData[ _iSlot ];
		}

		inline TData&           TakeNext( void )
		{
			//-----------------------------
			// precondition
			MB_ASSERT( muiNbData < MAXDATA - 1 , "Array full !\n" );
			//-----------------------------

			muiNbData++;
			return maData[ muiNbData - 1 ];
		}

		inline void             Clear( void )
		{
			muiNbData = 0;
		}
	};

	
	template< class TData, typename Counter >
	struct DynamicArray
	{
		TData*      maData;
		Counter     muiNbData;
		Counter     muiMaxData; 

		inline DynamicArray( void )
		:   maData      ( nullptr )
		,	muiNbData   ( 0 )
		,   muiMaxData	( 0 )
		{
		}

		inline DynamicArray( Counter _uiNbData )
		:   maData      ( nullptr )
		,	muiNbData   ( 0 )
		,   muiMaxData	( _uiNbData )
		{
			Allocate( _uiNbData );
		}

		inline ~DynamicArray( void )
		{
			if( nullptr != maData )
			{
				Deallocate();
			}
		}

		inline void             Allocate( UINT32 _uiNbData )
		{
			//-----------------------------
			// precondition
			MB_ASSERT( nullptr == maData , "Cannot Allocate : array already allocated !\n" );
			//-----------------------------

			muiMaxData	= _uiNbData;
			maData		= new TData[ _uiNbData ];
		}

		inline void             Deallocate( void )
		{
			//-----------------------------
			// precondition
			MB_ASSERT( nullptr != maData , "Cannot Deallocate : array not allocated !\n" );
			//-----------------------------
			delete [] maData;
			maData = nullptr;
		}
		
		inline UINT32			GetCapacity( void ) const
		{
			return muiMaxData;
		}

		inline Counter          GetSize( void ) const
		{
			return muiNbData;
		}
		 
		inline const TData&     operator[] ( int _iSlot ) const
		{
			return maData[ _iSlot ];
		}

		inline TData&           operator[] ( int _iSlot )
		{
			return maData[ _iSlot ];
		}

		inline TData&           TakeNext( void )
		{
			//-----------------------------
			// precondition
			MB_ASSERT( muiNbData < muiMaxData - 1 , "Array full !\n" );
			//-----------------------------

			muiNbData++;
			return maData[ muiNbData - 1 ];
		}

		inline void             Clear( void )
		{
			muiNbData = 0;
		}
	};


	 
	template< class TData >
	struct GrowingArray
	{
		UINT32      muiMaxData;
		UINT32      muiNbData;
		TData*      maData;

		inline GrowingArray( UINT32 _uiBaseSize )
		:   muiMaxData  ( _uiBaseSize )
		,   muiNbData   ( 0 )
		,   maData      ( nullptr )
		{
			Allocate( muiMaxData );
		}

		inline ~GrowingArray()
		{
			if( nullptr != maData )
			{
				Deallocate();
			}
		}

		inline void             Allocate( UINT32 _uiNbData )
		{
			//-----------------------------
			// precondition
			MB_ASSERT( nullptr == maData , "Cannot Allocate : array already allocated !\n" );
			//-----------------------------

			maData = new TData[ _uiNbData ];
		}

		inline void             Deallocate( void )
		{
			//-----------------------------
			// precondition
			MB_ASSERT( nullptr != maData , "Cannot Deallocate : array not allocated !\n" );
			//-----------------------------

			delete [] maData;
			maData = nullptr;
		}

		inline void             FLOATlocate(  UINT32 _uiNbData )
		{
			//-----------------------------
			// precondition
			MB_ASSERT( nullptr != maData , "Cannot FLOATlocate : array not allocated !\n" );
			//-----------------------------
 				
			// save previous data buffer
			TData* aPrev = maData;

			// increase the capacity
			muiMaxData	= _uiNbData; 

			// allocate the new buffer
			maData		= new TData[ _uiNbData ];

			// copy the previous data into the new buffer
			memcpy( maData, aPrev, sizeof( TData ) * muiNbData );
 
			// free the previous data buffer
			delete [] aPrev; 
		}

		inline UINT32          GetSize( void ) const
		{
			return muiNbData;
		}

		inline const TData&     operator[] ( int _iSlot ) const
		{
			return maData[ _iSlot ];
		}

		inline TData&           operator[] ( int _iSlot )
		{
			return maData[ _iSlot ];
		}

		inline TData&           TakeNext( void )
		{
			if( muiNbData >= muiMaxData )
			{ 
				FLOATlocate( muiMaxData * 2 ); 
			}
 
			muiNbData++;
			return maData[ muiNbData - 1 ];
		}

		inline void             Clear( void )
		{
			muiNbData = 0;
		}
	};

}